# coding=utf-8
import arcpy
import os
import sys
import traceback

# 设置默认编码为 UTF-8
try:
    reload(sys)
    sys.setdefaultencoding('utf-8')
except NameError:
    pass

# 配置参数
input_gdb = r"D:\ArcGis\DATA\TP_test.gdb"  # 输入GDB路径
output_gdb = r"D:\ArcGis\Output_test\TP_output.gdb"  # 输出GDB路径
target_feature_dataset = "TP_check"  # 目标要素数据集名称
output_suffix = "_LineOverlap_5m"  # 输出要素类的后缀
topology_errors_fc = r"D:\ArcGis\DATA\TP_erro.gdb\lineOverlap_line"  # 拓扑错误要素类路径
feature1_field = "OriginObjectID"  # 拓扑错误表中的要素ID字段
objectid_field = "OBJECTID"  # 原始要素类中的ID字段
overlap_tolerance = 0.00005  # 重叠容差值（单位与数据相同）

# 设置环境
arcpy.env.overwriteOutput = True
arcpy.env.workspace = os.path.join(input_gdb, target_feature_dataset)

# 字段类型映射，处理不同版本的差异
FIELD_TYPE_MAPPING = {
    "SmallInteger": "SHORT",
    "Integer": "LONG",
    "Single": "FLOAT",
    "Double": "DOUBLE",
    "String": "TEXT",
    "Date": "DATE",
    "OID": "LONG",
    "Geometry": None,
    "Blob": "BLOB",
    "Raster": "RASTER",
    "GUID": "GUID"
}

# 系统字段列表
SYSTEM_FIELDS = ['OBJECTID', 'SHAPE', 'SHAPE_LENGTH', 'SHAPE_AREA', 'OID@', 'SHAPE@']


def batch_process_overlaps():
    """批量处理线要素中的重叠部分，只剪除重复部分并保留属性"""
    try:
        # 检查拓扑错误要素类是否存在
        if not arcpy.Exists(topology_errors_fc):
            print("错误: 拓扑错误要素类 %s 不存在！" % os.path.basename(topology_errors_fc))
            return False

        # 创建输出GDB和要素数据集
        if not arcpy.Exists(output_gdb):
            create_gdb_if_not_exists(output_gdb)

        output_dataset = os.path.join(output_gdb, target_feature_dataset)
        if not arcpy.Exists(output_dataset):
            sr = arcpy.Describe(os.path.join(input_gdb, target_feature_dataset)).spatialReference
            arcpy.CreateFeatureDataset_management(output_gdb, target_feature_dataset, sr)

        # 获取需要处理的线要素类列表
        # 修正：使用 ListFeatureClasses() 而非 ListFields()
        line_fcs = arcpy.ListFeatureClasses(feature_type="Polyline")

        if not line_fcs:
            print("警告: 在 %s 中没有找到线要素类！" % target_feature_dataset)
            return False

        print("\n===== 开始批量处理重叠线（只剪除重复部分） =====")
        print("找到 %d 个线要素类需要处理" % len(line_fcs))
        print("使用拓扑错误要素类: %s" % os.path.basename(topology_errors_fc))
        print("关联字段: %s (拓扑错误表) -> %s (原始要素)" % (feature1_field, objectid_field))

        # 遍历线要素类进行处理
        for fc in line_fcs:
            fc_path = os.path.join(input_gdb, target_feature_dataset, fc)
            output_fc = os.path.join(output_dataset, fc + output_suffix)

            print("\n处理线要素类: %s" % fc)
            print("  输入: %s" % fc_path)
            print("  输出: %s" % output_fc)

            try:
                # 创建临时工作空间
                temp_gdb = os.path.join(os.path.dirname(output_gdb), "temp.gdb")
                if not arcpy.Exists(temp_gdb):
                    create_gdb_if_not_exists(temp_gdb)

                # 1. 处理重叠部分 - 只剪除重复部分
                print("  正在剪除重叠部分...")
                clip_overlapping_segments(fc_path, topology_errors_fc, output_fc,
                                          feature1_field, objectid_field)

                # 清理临时数据
                try:
                    arcpy.Delete_management(temp_gdb)
                    print("  临时数据清理完成")
                except:
                    print("  ! 临时工作空间锁定，无法删除")
                    pass

                # 获取处理结果统计
                input_count = int(arcpy.GetCount_management(fc_path).getOutput(0))
                output_count = int(arcpy.GetCount_management(output_fc).getOutput(0))
                print("  重叠处理完成 | 要素数量: 原始 %d -> 处理后 %d" % (input_count, output_count))

            except Exception as e:
                print("  处理失败: %s" % str(e))
                traceback.print_exc()
                continue

        print("\n===== 所有线要素类处理完成 =====")
        return True

    except Exception as e:
        print("执行过程中发生错误: %s" % str(e))
        traceback.print_exc()
        return False
    finally:
        arcpy.ResetEnvironments()


def create_gdb_if_not_exists(gdb_path):
    """创建文件地理数据库（如果不存在）"""
    try:
        if not arcpy.Exists(gdb_path):
            # 确保父目录存在
            parent_dir = os.path.dirname(gdb_path)
            if not os.path.exists(parent_dir):
                os.makedirs(parent_dir)
            arcpy.CreateFileGDB_management(os.path.dirname(gdb_path), os.path.basename(gdb_path))
            print("成功创建地理数据库: %s" % gdb_path)
        return True
    except Exception as e:
        print("创建地理数据库失败: %s, 错误: %s" % (gdb_path, str(e)))
        return False


def clip_overlapping_segments(feature_fc, error_fc, output_fc, feature1_field, objectid_field):
    """剪除重叠部分，保留非重叠部分及属性"""
    try:
        # 获取原始要素类的字段列表
        fields = arcpy.ListFields(feature_fc)

        # 创建输出要素类，包含所有原始字段
        arcpy.CreateFeatureclass_management(
            os.path.dirname(output_fc),
            os.path.basename(output_fc),
            "POLYLINE",
            feature_fc,
            spatial_reference=feature_fc
        )

        # 添加所有属性字段到输出要素类
        add_missing_fields(output_fc, feature_fc)

        # 1. 从拓扑错误表中提取错误要素的OBJECTID
        print("  从拓扑错误表中提取错误要素ID...")
        error_objectids = set()

        # 检查Feature 1字段是否存在
        error_fields = [f.name for f in arcpy.ListFields(error_fc)]
        if feature1_field not in error_fields:
            print("  错误: 拓扑错误要素类中不存在字段 %s" % feature1_field)
            return False

        with arcpy.da.SearchCursor(error_fc, [feature1_field]) as cursor:
            for row in cursor:
                if row[0]:  # 确保值不为None
                    error_objectids.add(row[0])

        print("  找到 %d 个存在拓扑错误的要素" % len(error_objectids))

        if not error_objectids:
            print("  没有找到需要处理的错误要素，直接复制原始数据")
            copy_old_to_new(output_fc, feature_fc)
            return True

        # 2. 选择存在拓扑错误的要素
        print("  选择存在拓扑错误的要素...")
        error_features_lyr = "error_features_lyr"
        arcpy.MakeFeatureLayer_management(feature_fc, error_features_lyr)

        # 构建WHERE子句
        where_clause = "%s IN (%s)" % (objectid_field, ','.join(map(str, error_objectids)))
        arcpy.SelectLayerByAttribute_management(error_features_lyr, "NEW_SELECTION", where_clause)

        # 检查是否有选择结果
        selected_count = int(arcpy.GetCount_management(error_features_lyr).getOutput(0))
        if selected_count == 0:
            print("  没有找到匹配的错误要素，直接复制原始数据")
            copy_old_to_new(output_fc, feature_fc)
            return True

        print("  找到 %d 个匹配的错误要素" % selected_count)

        # 3. 处理每个错误要素，删除其与拓扑错误要素的重叠部分并保留属性
        print("  处理每个错误要素，删除重叠部分...")

        # 创建临时要素类存储处理后的要素，包含所有属性字段
        temp_processed_fc = os.path.join(os.path.dirname(output_fc), "temp_processed")
        arcpy.CreateFeatureclass_management(
            os.path.dirname(temp_processed_fc),
            os.path.basename(temp_processed_fc),
            "POLYLINE",
            feature_fc,
            spatial_reference=feature_fc
        )

        # 添加所有属性字段到临时要素类
        add_missing_fields(temp_processed_fc, feature_fc)

        # 获取有效字段列表（排除系统字段）
        valid_fields = [f.name for f in fields if f.name.upper() not in SYSTEM_FIELDS]
        cursor_fields = ['SHAPE@', objectid_field] + valid_fields

        # 遍历每个错误要素，保留属性
        processed_count = 0
        with arcpy.da.SearchCursor(error_features_lyr, cursor_fields) as cursor:
            for row in cursor:
                geom = row[0]
                obj_id = row[1]
                attributes = row[2:]  # 提取属性值

                # 找到对应的拓扑错误记录
                error_geom = None
                where_clause = "%s = %d" % (feature1_field, obj_id)
                with arcpy.da.SearchCursor(error_fc, ['SHAPE@'], where_clause) as error_cursor:
                    for error_row in error_cursor:
                        error_geom = error_row[0]
                        break

                if error_geom:
                    # 计算要素与错误区域的差异（非重叠部分）
                    diff_geom = geom.difference(error_geom)

                    # 插入处理后的几何图形和属性
                    try:
                        with arcpy.da.InsertCursor(temp_processed_fc, ['SHAPE@'] + valid_fields) as insert_cursor:
                            insert_cursor.insertRow([diff_geom] + list(attributes))
                        processed_count += 1
                    except Exception as e:
                        print("    无法处理要素 %d: %s" % (obj_id, str(e)))

        print("  处理完成 %d 个要素，删除了重叠部分" % processed_count)

        # 4. 合并处理后的要素和未受影响的要素
        print("  合并处理后的要素和未受影响的要素...")

        # 选择未受影响的要素（没有拓扑错误的要素）
        unaffected_lyr = "unaffected_lyr"
        arcpy.MakeFeatureLayer_management(feature_fc, unaffected_lyr)
        where_clause = "%s NOT IN (%s)" % (objectid_field, ','.join(map(str, error_objectids)))
        arcpy.SelectLayerByAttribute_management(unaffected_lyr, "NEW_SELECTION", where_clause)

        # 将未受影响的要素追加到输出（保留属性）
        copy_old_to_new(output_fc, unaffected_lyr)

        # 将处理后的要素追加到输出（保留属性）
        if arcpy.Exists(temp_processed_fc):
            copy_old_to_new(output_fc, temp_processed_fc)

        # 5. 清理临时要素类
        print("  清理临时数据...")
        for fc_to_delete in [temp_processed_fc]:
            if arcpy.Exists(fc_to_delete):
                arcpy.Delete_management(fc_to_delete)

        print("  重叠部分剪除完成，属性已保留")
        return True

    except Exception as e:
        print("  重叠处理失败: %s" % str(e))
        traceback.print_exc()
        # 降级处理：复制原始要素（保留属性）
        copy_old_to_new(output_fc, feature_fc)
        return False


def add_missing_fields(new_fc, old_fc):
    """将旧数据中存在而新数据中不存在的属性字段添加到新数据中"""
    old_fields = arcpy.ListFields(old_fc)
    new_fields = [f.name.upper() for f in arcpy.ListFields(new_fc)]

    # 定义ArcGIS支持的字段类型
    supported_types = ['TEXT', 'FLOAT', 'DOUBLE', 'SHORT', 'LONG', 'DATE', 'BLOB', 'RASTER', 'GUID']

    for field in old_fields:
        # 跳过系统字段
        if field.name.upper() in SYSTEM_FIELDS:
            continue

        if field.name.upper() not in new_fields:
            field_name = field.name
            field_type = FIELD_TYPE_MAPPING.get(field.type, field.type)

            # 检查字段类型是否支持
            if field_type not in supported_types or field_type is None:
                print("警告: 字段 '%s' 的类型 '%s' 不支持，跳过添加" % (field_name, field.type))
                continue

            try:
                arcpy.AddField_management(new_fc, field_name, field_type)
                print("成功添加字段: %s (类型: %s)" % (field_name, field_type))
            except Exception as e:
                print("添加字段 '%s' 失败，类型: %s" % (field_name, field_type))
                print("错误详情: %s" % str(e))


def copy_old_to_new(new_fc, old_fc):
    """将旧数据复制到新数据中，自动处理字段匹配问题"""
    old_fields = [f.name for f in arcpy.ListFields(old_fc)]
    new_fields = [f.name for f in arcpy.ListFields(new_fc)]

    # 过滤掉系统字段，但保留SHAPE@用于几何
    old_fields_filtered = [f for f in old_fields if f.upper() not in SYSTEM_FIELDS]
    new_fields_filtered = [f for f in new_fields if f.upper() not in SYSTEM_FIELDS]

    # 添加几何字段
    old_fields_cursor = ['SHAPE@'] + old_fields_filtered
    new_fields_cursor = ['SHAPE@'] + new_fields_filtered

    # 构建字段映射
    field_mapping = []
    for new_field in new_fields_cursor:
        if new_field in old_fields_cursor:
            field_mapping.append(old_fields_cursor.index(new_field))
        else:
            field_mapping.append(None)

    # 执行数据复制
    print("开始复制数据...")
    count = 0
    try:
        with arcpy.da.InsertCursor(new_fc, new_fields_cursor) as insert_cursor:
            with arcpy.da.SearchCursor(old_fc, old_fields_cursor) as search_cursor:
                for row in search_cursor:
                    new_row = []
                    for idx in field_mapping:
                        if idx is None:
                            new_row.append(None)  # 新字段在旧数据中不存在，设为None
                        else:
                            new_row.append(row[idx])
                    insert_cursor.insertRow(new_row)
                    count += 1
                    if count % 1000 == 0:
                        print("已处理 %d 条记录" % count)
        print("共复制 %d 条记录" % count)
    except Exception as e:
        print("复制数据失败: %s" % str(e))
        traceback.print_exc()


if __name__ == "__main__":
    print("===== 开始批量处理拓扑重叠线（只剪除重复部分） =====")
    batch_process_overlaps()
    print("\n===== 程序执行完毕 =====")